/*
 * Part of the ACID Project
 * Developed in 2011 by Morgan Taschuk
 */
package acid.plugin.gui;

import cytoscape.Cytoscape;
import cytoscape.data.CyAttributes;
import cytoscape.visual.ArrowShape;
import cytoscape.visual.EdgeAppearanceCalculator;
import cytoscape.visual.GlobalAppearanceCalculator;
import cytoscape.visual.LineStyle;
import cytoscape.visual.NodeAppearanceCalculator;
import cytoscape.visual.NodeShape;
import cytoscape.visual.VisualPropertyType;
import cytoscape.visual.VisualStyle;
import cytoscape.visual.calculators.BasicCalculator;
import cytoscape.visual.calculators.Calculator;
import cytoscape.visual.customgraphic.CyCustomGraphics;
import cytoscape.visual.customgraphic.impl.bitmap.URLImageCustomGraphics;
import cytoscape.visual.mappings.BoundaryRangeValues;
import cytoscape.visual.mappings.ContinuousMapping;
import cytoscape.visual.mappings.DiscreteMapping;
import cytoscape.visual.mappings.Interpolator;
import cytoscape.visual.mappings.LinearNumberToColorInterpolator;
import cytoscape.visual.mappings.LinearNumberToNumberInterpolator;
import cytoscape.visual.mappings.PassThroughMapping;
import ding.view.ObjectPositionImpl;
import giny.view.Position;
import java.awt.Color;
import java.io.IOException;

/**
 *
 * @author morgan
 */
public class ACIDVisualStyle
{

    enum GraphicsPositions
    {

        POS1(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_1),
        POS2(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_2),
        POS3(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_3),
        POS4(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_4),
        POS5(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_5),
        POS6(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_6),
        POS7(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_7),
        POS8(VisualPropertyType.NODE_CUSTOM_GRAPHICS_POSITION_8);
        private VisualPropertyType vpt;

        GraphicsPositions(VisualPropertyType vpt)
        {
            this.vpt = vpt;
        }

        public VisualPropertyType getVpt()
        {
            return vpt;
        }
    }

    enum Graphics
    {

        POS1(VisualPropertyType.NODE_CUSTOM_GRAPHICS_1),
        POS2(VisualPropertyType.NODE_CUSTOM_GRAPHICS_2),
        POS3(VisualPropertyType.NODE_CUSTOM_GRAPHICS_3),
        POS4(VisualPropertyType.NODE_CUSTOM_GRAPHICS_4),
        POS5(VisualPropertyType.NODE_CUSTOM_GRAPHICS_5),
        POS6(VisualPropertyType.NODE_CUSTOM_GRAPHICS_6),
        POS7(VisualPropertyType.NODE_CUSTOM_GRAPHICS_7),
        POS8(VisualPropertyType.NODE_CUSTOM_GRAPHICS_8);
        private VisualPropertyType vpt;

        Graphics(VisualPropertyType vpt)
        {
            this.vpt = vpt;
        }

        public VisualPropertyType getVpt()
        {
            return vpt;
        }
    }



    public static final String vsName = "ACID Visual Style";


    private void setPosition(NodeAppearanceCalculator nodeAppCalc,
            VisualPropertyType vpt, Position p)
    {
        ObjectPositionImpl opi = new ObjectPositionImpl();
        opi.setAnchor(p);
        nodeAppCalc.getDefaultAppearance().set(vpt, opi);
    }

    private void arrangeCustomGraphics(NodeAppearanceCalculator nodeAppCalc)
    {
        GraphicsPositions[] vpts = GraphicsPositions.values();
        Position[] pts = Position.values();
        for (int i = 0; i < vpts.length; i++)
        {
            setPosition(nodeAppCalc, vpts[i].getVpt(), pts[i]);
        }
        CyCustomGraphics ccg = null;
        try
        {
            ccg = new URLImageCustomGraphics("http://cisban-silico.cs.ncl.ac.uk/images/cidlogosmall.png");
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

        CyAttributes attrs = Cytoscape.getNodeAttributes();
        Graphics[] gs = Graphics.values();
        int count = 0;
        for (String s : attrs.getAttributeNames())
        {
            if (s.startsWith(ConfigurationOptions.URL_ATT) && count < 8)
            {
                PassThroughMapping urlpm = new PassThroughMapping(ccg.getClass(), s);
                Calculator urlc = new BasicCalculator("Node Custom Graphic Calculator",
                        urlpm, gs[count++].getVpt());
                nodeAppCalc.setCalculator(urlc);
            }
        }



    }

    public VisualStyle createVisualStyle()
    {
        //make the visual style
        VisualStyle visualStyle = new VisualStyle(vsName);

        GlobalAppearanceCalculator globalAppCalc = visualStyle.getGlobalAppearanceCalculator();

        //global attributes - DEFAULT
        globalAppCalc.setDefaultBackgroundColor(Color.white);
        globalAppCalc.setDefaultEdgeSelectionColor(Color.red);
        globalAppCalc.setDefaultEdgeReverseSelectionColor(Color.pink);
        globalAppCalc.setDefaultNodeSelectionColor(Color.red);
        globalAppCalc.setDefaultNodeReverseSelectionColor(Color.pink);

        //node attributes - DEFAULT
        NodeAppearanceCalculator nodeAppCalc = visualStyle.getNodeAppearanceCalculator();
        //node shape - circle
        nodeAppCalc.getDefaultAppearance().set(VisualPropertyType.NODE_SHAPE, NodeShape.RECT);
        nodeAppCalc.getDefaultAppearance().set(VisualPropertyType.NODE_FILL_COLOR, new Color(0, 204, 204));
        //node label color - black
        nodeAppCalc.getDefaultAppearance().set(VisualPropertyType.NODE_LABEL_COLOR, Color.black);
        nodeAppCalc.getDefaultAppearance().set(VisualPropertyType.NODE_SIZE, 50);


        //node attributes - CALCULATED
        //node label
        PassThroughMapping pm = new PassThroughMapping(
                ConfigurationOptions.NAME_ATT.getClass(), ConfigurationOptions.NAME_ATT);
        Calculator nlc = new BasicCalculator("Node Label Calculator",
                pm, VisualPropertyType.NODE_LABEL);
        nodeAppCalc.setCalculator(nlc);
        //node image

        arrangeCustomGraphics(nodeAppCalc);

        //edge attributes - DEFAULT
        EdgeAppearanceCalculator edgeAppCalc = visualStyle.getEdgeAppearanceCalculator();
        //edge color
        edgeAppCalc.getDefaultAppearance().set(VisualPropertyType.EDGE_COLOR, Color.black);
        edgeAppCalc.getDefaultAppearance().set(VisualPropertyType.EDGE_OPACITY, 180);

        //edge attributes - CALCULATED
        //edge thickness
        ContinuousMapping widthMapping = new ContinuousMapping(new Integer(10).getClass(), 
                ConfigurationOptions.WEIGHT_ATT);
        widthMapping.setInterpolator(new LinearNumberToNumberInterpolator());
        BoundaryRangeValues min = new BoundaryRangeValues(0.1, 0.1, 0.1);
        BoundaryRangeValues max = new BoundaryRangeValues(100.0, 100.0, 100.0);
        widthMapping.addPoint(0.1, min);
        widthMapping.addPoint(100.0, max);
        Calculator widthCalculator = new BasicCalculator("width", widthMapping, VisualPropertyType.EDGE_LINE_WIDTH);
        edgeAppCalc.setCalculator(widthCalculator);

        //edge type
        DiscreteMapping lineStyleMapping = new DiscreteMapping(
                LineStyle.SOLID.getClass(), ConfigurationOptions.ESTABLISHED_ATT);
        lineStyleMapping.putMapValue("false", LineStyle.EQUAL_DASH);
        lineStyleMapping.putMapValue("true", LineStyle.SOLID);
        Calculator lineStyleCalculator = new BasicCalculator("line style", lineStyleMapping, VisualPropertyType.EDGE_LINE_STYLE);
        edgeAppCalc.setCalculator(lineStyleCalculator);

        //edge arrows
        DiscreteMapping sourceArrowMapping = new DiscreteMapping(
                ArrowShape.NONE.getClass(), ConfigurationOptions.DIRECTIONAL_ATT);
        sourceArrowMapping.putMapValue("false", ArrowShape.NONE);
        sourceArrowMapping.putMapValue("true", ArrowShape.CIRCLE);
        Calculator sourceArrowCalculator = new BasicCalculator("source arrow", sourceArrowMapping, VisualPropertyType.EDGE_SRCARROW_SHAPE);
        edgeAppCalc.setCalculator(sourceArrowCalculator);

        DiscreteMapping targetArrowMapping = new DiscreteMapping(
                ArrowShape.NONE.getClass(), ConfigurationOptions.DIRECTIONAL_ATT);
        targetArrowMapping.putMapValue("false", ArrowShape.NONE);
        targetArrowMapping.putMapValue("true", ArrowShape.ARROW);
        Calculator targetArrowCalculator = new BasicCalculator("target arrow", targetArrowMapping, VisualPropertyType.EDGE_TGTARROW_SHAPE);
        edgeAppCalc.setCalculator(targetArrowCalculator);

        //edge color
        ContinuousMapping continuousMapping = new ContinuousMapping(
                Color.black.getClass(), ConfigurationOptions.EXP_SIMILARITY_ATT);

        Interpolator numToColor = new LinearNumberToColorInterpolator();
        continuousMapping.setInterpolator(numToColor);

        Color underColor = Color.BLACK;
        Color minColor = new Color(255, 255, 204);
        Color maxColor = Color.GREEN;
        Color overColor = Color.green;
        BoundaryRangeValues bv0 = new BoundaryRangeValues(underColor, minColor, minColor);
        BoundaryRangeValues bv2 = new BoundaryRangeValues(maxColor, maxColor, overColor);
        continuousMapping.addPoint(0.0001, bv0);
        continuousMapping.addPoint(2.0, bv2);
        Calculator edgeColorCalculator = new BasicCalculator("Similarity Edge Color Calc",
                continuousMapping,
                VisualPropertyType.EDGE_COLOR);
        edgeAppCalc.setCalculator(edgeColorCalculator);

        visualStyle.setNodeAppearanceCalculator(nodeAppCalc);
        visualStyle.setEdgeAppearanceCalculator(edgeAppCalc);
        visualStyle.setGlobalAppearanceCalculator(globalAppCalc);

        return visualStyle;
    }
}
